package com.comac.print.component.app.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;

@Slf4j
public class HttpCustomUtil {
    public static String doGet(String url) {
        RestTemplate restTemplate;
        try {
            restTemplate = getRestTemplate();
            HttpHeaders requestHeaders = new HttpHeaders();
            requestHeaders.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<Object> httpEntity = new HttpEntity<>(requestHeaders);
            restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
            ResponseEntity<String> responseBodyEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
            if (!HttpStatus.OK.equals(responseBodyEntity.getStatusCode())) {
                return "";
            }
            return responseBodyEntity.getBody();
        } catch (Exception e) {
            log.error("发送GET请求异常,url:{},异常详情:", url, e);
            return "";
        }
    }

    public static String doPost(String url, Object requestBody) {
        return doPostWithAuth(url, "", requestBody);
    }

    public static String doPostWithAuth(String url, String basicAuth, Object requestBody) {
        RestTemplate restTemplate;
        try {
            restTemplate = getRestTemplate();
            HttpHeaders requestHeaders = new HttpHeaders();
            if (StringUtils.isNotBlank(basicAuth)) {
                requestHeaders.setBasicAuth(basicAuth);
            }
            requestHeaders.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<Object> httpEntity = new HttpEntity<>(requestBody, requestHeaders);
            restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
            ResponseEntity<String> responseBodyEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
            log.info("发送POST请求: 【url】"+url);
            log.info("发送POST请求: 【code】"+responseBodyEntity.getStatusCode()+"【body】"+responseBodyEntity.getBody());
            if (!HttpStatus.OK.equals(responseBodyEntity.getStatusCode())) {
                return "";
            }
            return responseBodyEntity.getBody();
        } catch (Exception e) {
            log.error("发送POST请求异常,url:{},异常详情:", url, e);
            return "";
        }
    }

    public static RestTemplate getRestTemplate() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(50000)
                .setConnectTimeout(50000)
                .setSocketTimeout(50000).build();
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build();
        HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
        SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", sslSocketFactory)
                .build();
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        connectionManager.setMaxTotal(200);
        connectionManager.setDefaultMaxPerRoute(100);

        HttpClientBuilder builder = HttpClientBuilder.create()
                .setDefaultRequestConfig(requestConfig)
                .setRetryHandler(new DefaultHttpRequestRetryHandler(3, false))
                .setSSLContext(sslContext)
                .setConnectionManager(connectionManager);
        HttpClient httpClient = builder.build();
        ClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        return new RestTemplate(clientHttpRequestFactory);
    }

    public static byte[] downloadFile(String url) {
        RestTemplate restTemplate;
        try {
            restTemplate = getRestTemplate();
            ResponseEntity<byte[]> responseBodyEntity = restTemplate.getForEntity(url, byte[].class);
            if (!HttpStatus.OK.equals(responseBodyEntity.getStatusCode())) {
                log.error("download url:{} fail,response code:{}", url, responseBodyEntity.getStatusCode());
            }

            return responseBodyEntity.getBody();
        } catch (Exception e) {
            log.error("下载请求异常,url:{},异常详情:", url, e);
        }
        return null;
    }
}
